/*
 * Copyright 2021 Readium Foundation. All rights reserved.
 * Use of this source code is governed by the BSD-style license
 * available in the top-level LICENSE file of the project.
 */

package org.readium.r2.shared.util.http

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import org.json.JSONObject
import org.readium.r2.shared.extensions.optNullableInt
import org.readium.r2.shared.extensions.optNullableString
import org.readium.r2.shared.util.logging.WarningLogger
import org.readium.r2.shared.util.logging.log

/**
 * Problem Details for HTTP APIs.
 *
 * https://tools.ietf.org/html/rfc7807
 *
 * @param title A short, human-readable summary of the problem type.
 * @param type A URI reference [RFC3986] that identifies the problem type. This specification
 *        encourages that, when dereferenced, it provide human-readable documentation for the
 *        problem type.
 * @param status The HTTP status code ([RFC7231], Section 6) generated by the origin server for this
 *        occurrence of the problem.
 * @param detail A human-readable explanation specific to this occurrence of the problem.
 * @param instance A URI reference that identifies the specific occurrence of the problem. It may or
 *        may not yield further information if dereferenced.
 */
@Parcelize
data class ProblemDetails(
    val title: String,
    val type: String? = null,
    val status: Int? = null,
    val detail: String? = null,
    val instance: String? = null
) : Parcelable {

    companion object {

        /**
         * Creates a [ProblemDetails] from its JSON representation.
         */
        fun fromJSON(json: JSONObject, warnings: WarningLogger? = null): ProblemDetails? {
            val title = json.optNullableString("title")
            if (title == null) {
                warnings?.log(ProblemDetails::class.java, "[title] is required", json)
                return null
            }

            return ProblemDetails(
                title = title,
                type = json.optNullableString("type"),
                status = json.optNullableInt("status"),
                detail = json.optNullableString("detail"),
                instance = json.optNullableString("instance")
            )
        }
    }
}
